package com.ckerchina.admin.ckadmin.service;

import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Decoder;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * Created by 晓丰 on 2016/1/21.
 */
@Service
public class RsaService { 

    private static final String ALGORITHM = "RSA";
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;


    private String privateKeyString="MIICXQIBAAKBgQDAOmWNy8j9gZstM1aFnINeMBY5yhwkZu1MG921E9fsQWx6FQQB\n" +
            "XBdw9HElQA8nBcghfqBLh+MLrQkUsLTLrF8PyDcS7AHZ7EwdvUHXzMOoSazK/ylN\n" +
            "AIOtrTIbTuLF5ZehWlKASH0Z8j61RauTu5groI6Yr9r9iVnWxRXnha+8LQIDAQAB\n" +
            "AoGBALjB6AXnjmEKBynkpA57plALC/GzbmUWgJGcXvXCAtDS+P5F4Lml1+n7KBzT\n" +
            "ezzYc8itukeebf007Ptz8/Gm1R3dsR+NIswKWCP9Gedm4he1q/V7qkNF7R+JPcbb\n" +
            "EsD88ZRK0G+Ju7P7HbJ2eA/522vdT0t8rMBLnrT8AXRMrZuBAkEA38qC4QJHpsaf\n" +
            "XGXBbIU0BzoiA7ZjS12zAUibBUbvFWdiDa00T2CGf/DVQ2NocX9Qtetk96DjRQi5\n" +
            "hqDqavGw/QJBANvk9jTIzFwVtlg4RKOOZsSAaqPPlF47KeUz9r7cVjNmXlC3ChOU\n" +
            "kyifaVXe9omKbK2MfxwId6jDEfeXyNr59vECQHKtRHnnAC5/E4R2hDKG441chbef\n" +
            "S6yAHE1pFj8TBUrTilR10Bto3CNNlwsMMqYOVp6SPFAEetGSUfeiF92rckUCQHNs\n" +
            "tzQz5tm7Z/Dc8GKuIBGrms6L6sSf57jxUucSv4jRhlZ2DisDBVAAhYlWtTCzYaKj\n" +
            "qiEr7KvAYZEGsp8HMPECQQDCRF/SsAonpwxVAl9Qr5Id/DolL4Pp7znPL8oadh05\n" +
            "cj0B/+IC0Lep+wpzH1je45/vW5XfEETC5/ULAnKZu6HT";

    private String publicKeyString="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAOmWNy8j9gZstM1aFnINeMBY5\n" +
            "yhwkZu1MG921E9fsQWx6FQQBXBdw9HElQA8nBcghfqBLh+MLrQkUsLTLrF8PyDcS\n" +
            "7AHZ7EwdvUHXzMOoSazK/ylNAIOtrTIbTuLF5ZehWlKASH0Z8j61RauTu5groI6Y\n" +
            "r9r9iVnWxRXnha+8LQIDAQAB";

    PrivateKey privateKey;

    PublicKey publicKey;

    @PostConstruct
    public void init() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
        privateKey=getPrivateKey(privateKeyString);
        publicKey=getPublicKey(publicKeyString);
    }

    private PrivateKey getPrivateKey(String keyString) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        BASE64Decoder base64Decoder= new BASE64Decoder();
        byte[] buffer= base64Decoder.decodeBuffer(keyString);
        RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(buffer));
        RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
        KeyFactory keyFactory= KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(rsaPrivKeySpec);
    }

    private PublicKey getPublicKey(String keyString) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        BASE64Decoder base64Decoder= new BASE64Decoder();
        byte[] buffer= base64Decoder.decodeBuffer(keyString);
        KeyFactory keyFactory= KeyFactory.getInstance("RSA");
        X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer);
        return  (RSAPublicKey) keyFactory.generatePublic(keySpec);

    }

    /**
     * 加密方法
     * @param source 源数据
     * @return
     * @throws Exception
     */
    public byte[] encrypt(Key publicKey, String source) throws Exception {
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] b = source.getBytes();
        int inputLen = b.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(b, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(b, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();

        /** 执行加密操作 */
        return encryptedData;
    }

    /**
     * 解密算法
     * @param encryptedData    密文
     * @return
     * @throws Exception
     */
    public byte[] decrypt(Key privateKey, byte[] encryptedData) throws Exception {
        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }



    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    public PublicKey getPublicKey() {
        return publicKey;
    }

    public static void main(String[] args) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {

        RsaService rsaService=new RsaService();
        rsaService.init();
        //测试字符串
        String encryptStr= "Test String chaijunkunTest String chaijunkun" +
                "Test String chaijunkunTest String chaijunkunTest String chaijunkun" +
                "Test String chaijunkunTest String chaijunkunTest String chaijunkun" +
                "Test String chaijunkunTest String chaijunkunTest String chaijunkun" +
                "Test String chaijunkunTest String chaijunkun";

        try {
            //加密
            byte[] cipher = rsaService.encrypt(rsaService.publicKey, encryptStr);
            //解密
            byte[] plainText = rsaService.decrypt(rsaService.privateKey, cipher);
            System.out.println("密文长度:"+ cipher.length);
            System.out.println(new String(cipher));
            System.out.println("明文长度:"+ plainText.length);
            System.out.println(new String(plainText));
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println(e.getMessage());
        }
    }
}
